package meta.symbolsAndTime.SAUNA;

import java.util.HashMap;
import java.util.List;

import multi.SAUNA.TemporalPolyhedron;
import org.metacsp.utility.UI.GraphFrame;
import edu.uci.ics.jung.algorithms.shortestpath.BFSDistanceLabeler;
import edu.uci.ics.jung.graph.ObservableGraph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import org.metacsp.framework.ConstraintNetwork;
import org.metacsp.framework.Variable;
import org.metacsp.framework.VariableOrderingH;

public class SpatialProximityVarOH extends VariableOrderingH {

	private HashMap<ConstraintNetwork,Integer> numberOfNeighbors;
	private UndirectedSparseGraph<ConstraintNetwork,String> g;
	protected ObservableGraph<ConstraintNetwork,String> graph;
	
	@Override
	public int compare(ConstraintNetwork arg0, ConstraintNetwork arg1) {
		return numberOfNeighbors.get(arg1) - numberOfNeighbors.get(arg0); 
	}

	@Override
	public void collectData(ConstraintNetwork[] allMetaVariables) {
		g = new UndirectedSparseGraph<ConstraintNetwork, String>();
		graph = new ObservableGraph<ConstraintNetwork, String>(g);
		int counter = 0;
		for (ConstraintNetwork oneMV : allMetaVariables) {
			for (Variable v : oneMV.getVariables()) {
				TemporalPolyhedron oneCP = (TemporalPolyhedron)v;
				ConstraintNetwork[] oldVertices = graph.getVertices().toArray(new ConstraintNetwork[graph.getVertexCount()]); 
				for (ConstraintNetwork cn : oldVertices) {
					for (Variable vOld : cn.getVariables()) {
						TemporalPolyhedron oneCPOld = (TemporalPolyhedron)vOld;
						if (oneCPOld.equals(oneCP) || oneCP.getSpatialPolyhedron().intersects(oneCPOld.getSpatialPolyhedron())) {
							if (!graph.containsVertex(oneMV)) graph.addVertex(oneMV);
							if (!graph.isNeighbor(oneMV, cn)) graph.addEdge((""+counter++), oneMV, cn);
							break;
						}
					}
				}
				if (!graph.containsVertex(oneMV)) graph.addVertex(oneMV);
			}
		}

		//Do a BFS to find connected components
		BFSDistanceLabeler<ConstraintNetwork,String> dl = new BFSDistanceLabeler<ConstraintNetwork,String>();
		numberOfNeighbors = new HashMap<ConstraintNetwork, Integer>();
		while (graph.getVertices().iterator().hasNext()) {
			ConstraintNetwork root = graph.getVertices().iterator().next();
			dl.labelDistances(graph, root);
			List<ConstraintNetwork> visited = dl.getVerticesInOrderVisited();
			for (ConstraintNetwork oneVisited : visited) {
				numberOfNeighbors.put(oneVisited, visited.size());
				graph.removeVertex(oneVisited);
			}
		}
		//this.draw("Hej there");
	}
	
	public void draw(String title) {
		new GraphFrame(graph, title);
	}


}
